package v4

import (
	"bytes"
	"crypto/sha256"
	"encoding/gob"
	"fmt"
	"log"
)

const (
	reward = 50.00
)

// 交易结构对象
type Transaction struct {
	//交易id
	TXID []byte
	//交易输出信息
	TxOutputs []TxOutput
	//交易输入信息
	TxInputs []TxInput
}

// 设置交易的hash为交易ID
func (t *Transaction) SetHash() {
	var buffer = bytes.Buffer{}
	enc := gob.NewEncoder(&buffer)
	err := enc.Encode(t)
	if err != nil {
		log.Panic(err)
	}
	sum256 := sha256.Sum256(buffer.Bytes())
	t.TXID = sum256[:]
}

// 输出对象
type TxOutput struct {
	//金额
	Value float64
	//锁定脚本
	ScriptPubKey string
}

// 输入对象
type TxInput struct {
	//关联的上一笔的交易id
	TxID []byte
	//关联的上一笔的输出的索引值(第几笔输出)
	Index int64
	//解锁脚本-签名
	Sig string
}

// 定义一笔挖矿交易
func NewCoinbaseTransaction(addr string, data string) *Transaction {
	var txOutput = TxOutput{
		reward,
		addr,
	}
	var txInput = TxInput{
		[]byte{},
		-1,
		data, //一般为矿池名称
	}
	var t = Transaction{
		[]byte{},
		[]TxOutput{txOutput},
		[]TxInput{txInput},
	}
	t.SetHash()
	return &t
}

// 是否是挖矿所得的交易
func (t *Transaction) IsCoinbase() bool {
	if len(t.TxInputs) == 1 {
		input := t.TxInputs[0]
		if input.Index == -1 && input.TxID == nil {
			return true
		}
	}
	return false
}

// 定义一笔普通交易
func NewTransaction(from, to string, amount float64, bc *BlockChain) *Transaction {
	utxOs, total := bc.FindSuitableUTXOs(from, amount)
	if total < amount {
		fmt.Println("交易失败,余额不足")
		return nil
	}
	var TxInputs []TxInput
	var txOutput = TxOutput{
		amount,
		to,
	}
	var TxOutputs = []TxOutput{txOutput}
	for UXID, indexArrays := range utxOs {
		for _, index := range indexArrays {
			var txInput = TxInput{
				[]byte(UXID),
				index,
				from, //一般为矿池名称
			}
			TxInputs = append(TxInputs, txInput)
		}
	}
	if total > amount {
		//余额转入自身
		var txOutput0 = TxOutput{
			total - amount,
			from,
		}
		TxOutputs = append(TxOutputs, txOutput0)
	}
	var tx = Transaction{
		nil,
		TxOutputs,
		TxInputs,
	}
	tx.SetHash()
	return &tx
}
